#include "time_util.hh"
#include <chrono>

#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif

namespace kratos {
namespace util {
std::time_t last_updating_millionsecond = 0;
std::time_t begin_frame_millionsecond = 0;
std::time_t current_frame_cost_millionsecond = 0;
std::time_t lowest_cost_millionsecond = 0;
std::time_t highest_cost_millionsecond = 0;
} // namespace util
} // namespace kratos

auto kratos::util::get_os_time_millionsecond() -> std::time_t {
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::system_clock::now().time_since_epoch())
                .count();
  return ms;
}

auto kratos::util::get_last_timestamp_millionsecond() -> std::time_t {
  return last_updating_millionsecond;
}

auto kratos::util::set_last_timestamp_millionsecond(std::time_t now) -> void {
  last_updating_millionsecond = now;
}

auto kratos::util::get_lowest_cost_millionsecond() -> std::time_t {
  return lowest_cost_millionsecond;
}

auto kratos::util::get_highest_cost_millionsecond() -> std::time_t {
  return highest_cost_millionsecond;
}

auto kratos::util::set_frame_begin(std::time_t now) -> void {
  begin_frame_millionsecond = now;
}

auto kratos::util::set_frame_end(std::time_t now) -> void {
  auto gap = now - begin_frame_millionsecond;
  current_frame_cost_millionsecond = gap;
  if (0 == lowest_cost_millionsecond) {
    lowest_cost_millionsecond = gap;
  } else {
    if (gap < lowest_cost_millionsecond) {
      lowest_cost_millionsecond = gap;
    }
  }
  if (0 == highest_cost_millionsecond) {
    highest_cost_millionsecond = gap;
  } else {
    if (gap > highest_cost_millionsecond) {
      highest_cost_millionsecond = gap;
    }
  }
}

auto kratos::util::get_real_frame() -> int {
  if (0 == current_frame_cost_millionsecond) {
    return 1000;
  }
  return (int)(1000 / current_frame_cost_millionsecond);
}

auto kratos::util::get_current_cost_millionsecond() -> std::time_t {
  return current_frame_cost_millionsecond;
}

auto kratos::util::get_os_time_microsecond() -> std::time_t {
#ifdef WIN32
  LARGE_INTEGER freq;
  LARGE_INTEGER fc;
  if (!::QueryPerformanceFrequency(&freq)) {
    return 0;
  }
  if (!::QueryPerformanceCounter(&fc)) {
    return 0;
  }
  return fc.QuadPart / (freq.QuadPart / 1000 / 1000);
#else
  struct timeval tv;
  uint64_t ms;
  gettimeofday(&tv, 0);
  ms = tv.tv_sec * 1000 * 1000;
  ms += tv.tv_usec;
  return ms;
#endif // WIN32
}
